package testsUnitaires;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

import security.aes.AES256;

public class TestAES256 {

	/**
	 * Main de test de la classe de chiffrement AES256
	 * Etapes de l'algo :
	 * 1) créer/charger la clé AES (aléatoirement, ou génération/chargement depuis un Keystore)
	 * 2) initialisation de l'objet Cipher
	 * 3) chiffrement
	 * 4) déchiffrement
	 * Cet exemple chiffre un texte
	 * On peut aussi chiffrer une image sous format .BMP dans la partie concernée
	 * Attention aux chemins utilisés !
	 * @param args
	 */
	public static void main(String[] args) {

		System.out.println("Test propre:");
		String data = "Plip Plip Tagada Tsoin Tsoin On Teste Blabla =D";
		System.out.println("Texte initial:\t"+data);


		//final String ksPath = "C:\\Users\\B182JS\\workspace\\projet_SmartCard\\bin\\aesKeyStore.keystore";
		final String ksPath = "C:\\Users\\B182JS\\workspace\\vsm\\bin\\aesKeyStore.keystore";
		
		//TODO générer aléatoirement deux tableaux de chars qu'on stocke en BDD ?
		final char[] ksPassword = {'t','o','t','o'};
		final char[] keyPassword = {'t','o','t','o'};
		String alias = "aesKey";

		//TODO générer un alias différent à chaque keystore ?
		//TODO commenter si déjà créé
		AES256.createAESKeyStore(ksPath, ksPassword, keyPassword, alias);

		SecretKey aesKey = null;

		//TODO choisir le chargement de la clé
		// Load Key From Keystore
		aesKey = AES256.loadKeyFromKeyStore(ksPath, ksPassword, keyPassword, alias);

		// Generate key
		//aesKey = AES256.generateRandomKey();

		// Init cipher
		//TODO stocker en BDD l'iv et le charger
		byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
	    IvParameterSpec ivspec = new IvParameterSpec(iv);
	    
		Cipher encryptCipher = AES256.initCipherEncrypt(aesKey, ivspec);
		Cipher decryptCipher = AES256.initCipherDecrypt(aesKey, ivspec);

		// Crypt and Decrypt
		byte[] encryptedData = AES256.encrypt(data.getBytes(),aesKey,encryptCipher);
		byte[] decryptedData = AES256.decrypt(encryptedData,aesKey,decryptCipher);

		// Show Result
		System.out.println("Résultat:\t"+new String(decryptedData));
		
		//test video
		System.out.println("\nTestVideo!");
		byte[] iv2 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
	    IvParameterSpec ivspec2 = new IvParameterSpec(iv2);
				
		// Create new Keystore
	    String newKeystorePath = "C:\\Users\\B182JS\\workspace\\aesKeyStoreTEST.keystore";
	    AES256.createAESKeyStore(newKeystorePath, ksPassword, keyPassword, alias);
	    
	    aesKey = AES256.loadKeyFromKeyStore(newKeystorePath, ksPassword, keyPassword, alias);
		Cipher encryptCipher2 = AES256.initCipherEncrypt(aesKey, ivspec2);
		String pathFile = "C:\\Users\\B182JS\\workspace\\CAM42-192.168.2.42_20140603_162058-010.mp4";
		//String pathFile = "C:\\Documents and Settings\\Guillaume\\workspace\\testTexte.txt";
		//String newPathFile = "C:\\Documents and Settings\\Guillaume\\workspace\\TOTO.txt";
		String newPathFile = "C:\\Users\\B182JS\\workspace\\TOTO.mp4";
		String encryptFile = pathFile+".encrypt";
		
		//AES256.encryptInputFile(pathFile, encryptFile, encryptCipher2);
		AES256.encryptInputFile(pathFile, encryptFile, newKeystorePath, ksPassword, keyPassword, alias, iv2);
		
		/*
		int next, len = 1024, size = 0;
		 
		byte[] encryptedData2, decryptedData2; 
		
    	byte[] b = new byte[len];
		
	    try {
	    	FileInputStream input = new FileInputStream(new File(pathFile));
			FileOutputStream out = new FileOutputStream(new File(encryptFile));
			
			while((next = input.read(b,0,len)) != -1){
				//encryptedData2 = AES256.encrypt(b,aesKey,encryptCipher2);
				if(next == len){
					//System.out.println("CHIFFRETagadaOK");
					//encryptedData2 = encryptCipher2.update(b);
					encryptedData2 = AES256.encryptUpdate(b, encryptCipher2);
					out.write(encryptedData2,0,encryptedData2.length);
				}
				else{
					System.out.println("CHIFFRETagadaNONOK:"+next);
					//encryptedData2 = encryptCipher2.doFinal(b,0,next);
					encryptedData2 = AES256.encryptFinal(b, encryptCipher2, next);
					System.out.println(encryptedData2.length);
					out.write(encryptedData2,0,encryptedData2.length);
				}
				//System.out.println(next+"&"+Math.min(next, encryptedData2.length));
				//out.write(encryptedData2,0,next);
				out.flush();
				size += encryptedData2.length;
				//out.write(encryptedData2,0,Math.min(next, encryptedData2.length));
				//out.write(encryptedData2,0,encryptedData2.length);
			}
			System.out.println("TotalSizeCrypt:"+size);
			//out.flush();
			input.close();
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	    */
	    aesKey = AES256.loadKeyFromKeyStore(newKeystorePath, ksPassword, keyPassword, alias);
	    Cipher decryptCipher2 = AES256.initCipherDecrypt(aesKey, ivspec2);
	    
	    //AES256.decryptInputFile(encryptFile, newPathFile, decryptCipher2);
	    AES256.decryptInputFile(encryptFile, newPathFile, newKeystorePath, ksPassword, keyPassword, alias, iv2);
	    
	    /*
	    try {
	    	FileInputStream input = new FileInputStream(new File(encryptFile));
	    	FileOutputStream out = new FileOutputStream(new File(newPathFile));
			next = 0;
			size = 0;
			len = 1024;
			b = new byte[len];

			while((next = input.read(b,0,len)) != -1){
				//decryptedData2 = AES256.decrypt(b,aesKey,decryptCipher2);
				if(next == len){
					//System.out.println("TagadaOK");
					//decryptedData2 = decryptCipher2.update(b);
					decryptedData2 = AES256.decryptUpdate(b, decryptCipher2);
					out.write(decryptedData2,0,decryptedData2.length);
					if(decryptedData2.length != len)	System.out.println("TagadaOKWTF\tDecryptLen:"+decryptedData2.length+"&len:"+len);
				}
				else{
					System.out.println("TagadaNONOK:"+next);
					//decryptedData2 = decryptCipher2.doFinal(b,0,next);
					decryptedData2 = AES256.decryptFinal(b, decryptCipher2, next);
					System.out.println(decryptedData2.length);
					out.write(decryptedData2,0,decryptedData2.length);
				}
				//out.write(decryptedData2,0,next);
				//out.write(decryptedData2,0,Math.min(next, decryptedData2.length));
				out.flush();
				size += decryptedData2.length;
				//out.write(decryptedData2,0,decryptedData2.length);
			}
			//out.flush();
			System.out.println("TotalSizeDecrypt:"+size);
			input.close();
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		*/
	    
	    System.out.println("Fin TestVideo!");

	    /*
		System.out.println("\nTest image:");

		String imgPath = "C:\\Documents and Settings\\Guillaume\\workspace\\tests\\lena.bmp";
		String imgPathCrypt = "C:\\Documents and Settings\\Guillaume\\workspace\\tests\\lena_crypt.bmp";
		String imgPath2 = "C:\\Documents and Settings\\Guillaume\\workspace\\tests\\lena_.bmp";

		FileInputStream r1, r2 = null;
		FileOutputStream w1, w2 = null;

		int offset_to_data = -14;
		int tmp = 0, d = 0;
		String buffer = "";
		byte[] bmp, buff2;
		int BUF_LEN = 1024;
		long timestamp = System.currentTimeMillis();

		try {
			KeyGenerator kgen2 = KeyGenerator.getInstance("AES");
			kgen2.init(256);
			SecretKey aesKey2 = kgen2.generateKey();

			// Encrypt cipher
			Cipher encryptCipherImg;
			encryptCipherImg = Cipher.getInstance("AES/CBC/PKCS5Padding");
			encryptCipherImg.init(Cipher.ENCRYPT_MODE, aesKey2);

			//chiffrement image
			r1 = new FileInputStream(imgPath);			
			w1 = new FileOutputStream(imgPathCrypt);

			// skip header (10 octets)
			for(int i=10;i>0;i--)
				w1.write(r1.read());

			// read offset (be) to bmp data, converted to le
			for(int i=0;i<4;i++) {
				tmp = r1.read();
				w1.write(tmp);
				offset_to_data += tmp*Math.pow(256, i);
			}

			// skip to data
			for(int i=offset_to_data;i>0;i--)
				w1.write(r1.read());

			DataInputStream dis = new DataInputStream(r1);
			int tailleImage = dis.available();
			System.out.println("Taille image : "+tailleImage+" et offset_to_data "+offset_to_data);

			bmp = new byte[tailleImage];
			buff2 = new byte[tailleImage];

			int z = 0;
			while(r1.read(bmp) != -1){
				//System.out.println("iteration "+z);
				z++;
				buff2 = AES256.encrypt(bmp,aesKey2,encryptCipherImg);
				w1.write(buff2);
			}

			r1.close();
			w1.close();
			System.out.println("Temps chiffrement: "+(System.currentTimeMillis()-timestamp)+"ms");

			//dechiffrement image
			timestamp = System.currentTimeMillis();
			r2 = new FileInputStream(imgPathCrypt);
			w2 = new FileOutputStream(imgPath2);

			//bmp = new byte[BUF_LEN];
			//buff2 = new byte[BUF_LEN];
			//System.out.println(r.available());

			// skip header (10 octets)
			for(int i=10;i>0;i--)
				w2.write(r2.read());

			// read offset (be) to bmp data, converted to le
			offset_to_data = -14;
			for(int i=0;i<4;i++) {
				tmp = r2.read();
				w2.write(tmp);
				offset_to_data += tmp*Math.pow(256, i);
			}

			// skip to data
			for(int i=offset_to_data;i>0;i--)
				w2.write(r2.read());

			DataInputStream dis2 = new DataInputStream(r2);
			int tailleImage2 = dis2.available();
			System.out.println("Taille image : "+tailleImage+" et offset_to_data "+offset_to_data);

			bmp = new byte[tailleImage2];
			buff2 = new byte[tailleImage2];

			z = 0;
			while(r2.read(bmp) != -1){
				//System.out.println("iteration2 "+z);
				z++;
				buff2 = AES256.decrypt(bmp,aesKey2,encryptCipherImg);
				w2.write(buff2);
			}

			r2.close();
			w2.close();

			System.out.println("Temps dechiffrement: "+(System.currentTimeMillis()-timestamp)+"ms");

		} catch (IOException e1) {
			e1.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}*/

	}

}
